package thomas.javase.collection;

import lombok.Data;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class MapTest {

    @Test
    public void testMap1(){
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "linode.com");
        map.put(2, "something");
        map.put(3, "something");
        map.put(4, "heroku.com");

        //Map -> Stream -> Filter -> String
        //somethingsomething
        String result = map.entrySet().stream()
                .filter(x -> "something".equals(x.getValue()))
                .map(x->x.getValue())
                .collect(Collectors.joining());
        System.out.println(result);

        //Map -> Stream -> Filter -> MAP
        //{2=something}
        Map<Integer, String> collect = map.entrySet().stream()
                .filter(x -> x.getKey() == 2)
                .collect(Collectors.toMap(x -> x.getKey(), x -> x.getValue()));
        System.out.println(collect);

        // or like this
        // {3=something}
        Map<Integer, String> collect2 = map.entrySet().stream()
                .filter(x -> x.getKey() == 3)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        System.out.println(collect2);
    }

    @Test
    public void testMap2(){
        Map<Integer, String> HOSTING = new HashMap<>();
        HOSTING.put(1, "linode.com");
        HOSTING.put(2, "heroku.com");
        HOSTING.put(3, "digitalocean.com");
        HOSTING.put(4, "aws.amazon.com");

        // Before Java 8
        String result = "";
        for (Map.Entry<Integer, String> entry : HOSTING.entrySet()) {
            if ("aws.amazon.com".equals(entry.getValue())) {
                result = entry.getValue();
            }
        }
        System.out.println("Before Java 8 : " + result);

        //Map -> Stream -> Filter -> String
        result = HOSTING.entrySet().stream()
                .filter(map -> "aws.amazon.com".equals(map.getValue()))
                .map(map -> map.getValue())
                .collect(Collectors.joining());

        System.out.println("With Java 8 : " + result);

        // filter more values
        result = HOSTING.entrySet().stream()
                .filter(x -> {
                    if (!x.getValue().contains("amazon") && !x.getValue().contains("digital")) {
                        return true;
                    }
                    return false;
                })
                .map(map -> map.getValue())
                .collect(Collectors.joining(","));

        System.out.println("With Java 8 : " + result);
    }

    @Test
    public void testMap3(){
        Map<Integer, String> HOSTING = new HashMap<>();
        HOSTING.put(1, "linode.com");
        HOSTING.put(2, "heroku.com");
        HOSTING.put(3, "digitalocean.com");
        HOSTING.put(4, "aws.amazon.com");
        HOSTING.put(5, "aws2.amazon.com");

        //  {1=linode.com}
        Map<Integer, String> filteredMap = filterByValue(HOSTING, x -> x.contains("linode"));
        System.out.println(filteredMap);

        // {1=linode.com, 4=aws.amazon.com, 5=aws2.amazon.com}
        Map<Integer, String> filteredMap2 = filterByValue(HOSTING, x -> (x.contains("aws") || x.contains("linode")));
        System.out.println(filteredMap2);

        // {4=aws.amazon.com}
        Map<Integer, String> filteredMap3 = filterByValue(HOSTING, x -> (x.contains("aws") && !x.contains("aws2")));
        System.out.println(filteredMap3);

        // {1=linode.com, 2=heroku.com}
        Map<Integer, String> filteredMap4 = filterByValue(HOSTING, x -> (x.length() <= 10));
        System.out.println(filteredMap4);
    }

    // Generic Map filterbyvalue, with predicate
    public static <K, V> Map<K, V> filterByValue(Map<K, V> map, Predicate<V> predicate) {
        return map.entrySet()
                .stream()
                .filter(x -> predicate.test(x.getValue()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    @Test
    public void testMapPoint(){
        Map<Integer, MyWebDriver> myWebDriverPool = new ConcurrentHashMap<>();
        myWebDriverPool.put(1, new MyWebDriver("driver1", true));
        myWebDriverPool.put(2, new MyWebDriver("driver2"));
        myWebDriverPool.put(3, new MyWebDriver("driver3"));
        final MyWebDriver myWebDriver =this.getMyWebDriver(myWebDriverPool);
        //{1=MapTest.MyWebDriver(used=true, name=driver1), 2=MapTest.MyWebDriver(used=true, name=driver2), 3=MapTest.MyWebDriver(used=false, name=driver3)}
        System.out.println(myWebDriverPool);
        this.returnMyWebDriver(myWebDriver);
        //{1=MapTest.MyWebDriver(used=true, name=driver1), 2=MapTest.MyWebDriver(used=false, name=driver2), 3=MapTest.MyWebDriver(used=false, name=driver3)}
        System.out.println(myWebDriverPool);
    }

    @Test
    public void testMap4() {
        IntStream.range(0, 20).forEach(i -> System.out.println(i));
        //IntStream.range(0, 20).mapToObj(i -> this.myWebDriverPool.put(i, this.initialWebserver(i)));
    }

    public synchronized MyWebDriver getMyWebDriver(Map<Integer, MyWebDriver> myWebDriverPool){
        final MyWebDriver myWebDriver = myWebDriverPool.entrySet().stream()
                .filter(entry -> !entry.getValue().isUsed())
                .map(Map.Entry::getValue)
                .findFirst()
                .orElse(null);
        myWebDriver.setUsed(true);
        return myWebDriver;
    }

    public synchronized void returnMyWebDriver(MyWebDriver myWebDriver){
        myWebDriver.setUsed(false);
    }

    @Data
    class MyWebDriver{
        private boolean used;
        private String name;

        public MyWebDriver(String name){
            this.name = name;
        }

        public MyWebDriver(String name, boolean used){
            this.name = name;
            this.used = used;
        }

    }

}
